package com.epam.task.xml.parsers;

import com.epam.task.xml.classes.*;
import com.epam.task.xml.classes.Package;
import com.epam.task.xml.enums.Group;
import com.epam.task.xml.enums.Measure;
import com.epam.task.xml.enums.PackageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class DOMAnalyzer {
    public static final Logger LOGGER = LoggerFactory.getLogger(DOMAnalyzer.class);
    DocumentBuilderFactory factory;
    DocumentBuilder builder;
    Document document;
    Element root;
    List<Medicine> medicines;

    public DOMAnalyzer(String xmlFile) {
        LOGGER.info("DOM parsing started...");
        try {
            factory = DocumentBuilderFactory.newInstance();
            builder = factory.newDocumentBuilder();
            document = builder.parse(xmlFile);
            root = document.getDocumentElement();
            medicines = listBuilder(root);
        } catch (SAXException e) {
            e.printStackTrace();
            LOGGER.warn("ошибка SAXAnalyzer парсера");
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
            LOGGER.error("ошибка конфигурации");
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("ошибка I/О потока");
        }
        for (int i = 0; i < medicines.size(); i++) {
            LOGGER.warn(medicines.get(i).toString());
        }
        LOGGER.info("DOM parsing end.");
    }

    public static List<Medicine> listBuilder(Element root) throws SAXException, IOException {
        List<Medicine> medicines = new ArrayList<Medicine>();
        // получение списка дочерних элементов <medicine>
        NodeList medicinesNodes = root.getElementsByTagName("medicine");
        Medicine medicine = null;
        for (int i = 0; i < medicinesNodes.getLength(); i++) {
            medicine = new Medicine();
            // заполнение объекта medicine
            Element medicineElement = (Element) medicinesNodes.item(i);
            String valueGroup = medicineElement.getAttribute("group").toUpperCase();
            medicine.setGroup(Group.valueOf(valueGroup));
            medicine.setUid(medicineElement.getAttribute("uid"));
            medicine.setName(getBabyValue(medicineElement, "name"));
            medicine.setFactory(getBabyValue(medicineElement, "factory"));
            //заполнение объекта analog
            listBuilderAnalog(medicine, medicineElement);
            // заполнение объекта release
            Release release = medicine.getRelease();
            Element releaseElement = getBaby(medicineElement, "release");
            release.setNameRelease(getBabyValue(releaseElement, "nameRelease"));
            //заполнение объекта certificate
            Certificate certificate = release.getCertificate();
            Element certificateElement = getBaby(releaseElement, "certificate");
            certificate.setRegistrationCode(new Integer(getBabyValue(certificateElement, "registrationCode")));
            certificate.setDeadline(getBabyValue(certificateElement, "deadline"));
            certificate.setOrganization(getBabyValue(certificateElement, "organization"));
            //заполнение объекта package
            Package aPackage = release.getAPackage();
            Element packageElement = getBaby(releaseElement, "package");
            aPackage.setKind(PackageType.valueOf(getBabyValue(packageElement, "kind").toUpperCase()));
            aPackage.setCount(new Integer(getBabyValue(packageElement, "count")));
            aPackage.setPrice(new Integer(getBabyValue(packageElement, "price")));
            //заполнение объекта dosage
            Dosage dosage = release.getDosage();
            Element dosageElement = getBaby(releaseElement, "dosage");
            dosage.setDose(new Float(getBabyValue(dosageElement, "dose")));
            dosage.setMeasure(Measure.valueOf(getBabyValue(dosageElement, "measure").toUpperCase()));
            dosage.setFrequency(new Integer(getBabyValue(dosageElement, "frequency")));
            medicines.add(medicine);
        }// конец цикла for
        return medicines;
    }

    public static List<Analog> listBuilderAnalog(Medicine medicine, Element medicineElement) throws SAXException, IOException {
        List<Analog> analogs = medicine.getAnalogs();
        NodeList analogsNodes = medicineElement.getElementsByTagName("analog");
        Analog analog = null;
        for (int j = 0; j < analogsNodes.getLength(); j++) {
            analog = new Analog();
            Element analogElement = (Element) analogsNodes.item(j);
            analog.setAnalogId(getBabyValue(analogElement, "analogId"));
            analog.setNameAnalog(getBabyValue(analogElement, "nameAnalog"));
            analogs.add(analog);
        }
        return analogs;
    }

    // возвращает дочерний элемент по его имени и родительскому элементу
    private static Element getBaby(Element parent, String childName) {
        NodeList nlist = parent.getElementsByTagName(childName);
        Element child = (Element) nlist.item(0);
        return child;
    }

    // возвращает текст, содержащийся в элементе
    private static String getBabyValue(Element parent, String childName) {
        Element child = getBaby(parent, childName);
        Node node = child.getFirstChild();
        String value = node.getNodeValue();
        return value;
    }

}
